#pragma once

#include <string>

namespace terms {
	/**
	 * \brief Convert a list of objects into their string representations
	 * and join the results into a single string.
	 **/
	template <class Item>
	struct join {
		/**
		 * \brief Convert a list of objects into their string representations
		 * and join the results into a single string.
		 *
		 * \tparam Container The type of the input container.
		 * \param sep The separator between each container element
		 * \param container The container to use as input
		 * \param to_string The converter function to use for translating
		 * container elements into strings.
		 **/
		template <typename Container>
		std::string
		operator()(const std::string &sep, const Container &container, std::string (* to_string)(Item)) const
		{
			return (*this)(sep, container.begin(), container.end(), to_string);
		}

		/**
		 * \brief Convert a list of objects into their string representations
		 * and join the results into a single string.
		 *
		 * \tparam The type of the input iterators
		 * \param sep The separator between each element.
		 * \param to_string The converter function to use for
		 * translating * each element into a string.
		 **/
		template <typename Iter>
		std::string
		operator()(const std::string &sep, Iter begin, Iter end, std::string (* to_string)(Item)) const
		{
			std::string result;
			bool first = true;
			for (auto iter = begin; iter != end; ++iter) {
				if (! first) {
					result.append(sep);
				} else {
					first = false;
				}	
				result.append(to_string(*iter));
			}
			return result;
		}	
	};

	/**
	 * \brief Deference a pointer and convert the referenced object into
	 * a string representation.
	 *
	 * Uses \ref std::to_string()
	 * \tparam V the type of the object to convert (not the pointer's
	 * type)
	 * \param ptr The pointer to convert.
	 **/
	template <typename V>
	std::string
	ptr_to_string(const V *ptr)
	{
		return std::to_string(*ptr);
	}


 	/**
	 * \brief Deference a pointer and convert the referenced object into
	 * a string representation.
	 *
	 * Calls the supplied \p to_string function for the conversion.
	 *
	 * \tparam V the type of the object to convert (not the pointer's
	 * type)
	 * \param ptr The pointer to convert.
	 * \param to_string The conversion function to convert the
	 * referenced object to its string representation.
	 **/
	template <typename V>
	std::string
	ptr_to_string(const V *ptr, std::string (* to_string(const V &)))
	{
		return to_string(*ptr);
	}
}	

namespace std {
	/**
	 * \brief convert a string into a string.
	 *
	 * Do-nothing passthrough. STL does not have this.
	 **/
	string &to_string(string &str);

	/**
	 * \brief convert a string into a string.
	 *
	 * Do-nothing passthrough. STL does not have this.
	 **/
	string &to_string(string &str);
	const string &to_string(const string &str);
}
